#!/usr/bin/python

from __future__ import with_statement
from collections import defaultdict
import os.path
import re
import sys

from PyQt4.QtCore import Qt, QString
from PyQt4 import QtGui

from app import Application
from code_widget import CodeWidget
from user_prefs import UserPrefs

# TODO: Suppress Python's default console
# TODO: Kill halfhearted nt-from-within-Cygwin support in os_helpers and elsewhere

# When running under py2exe, add the native OS directory to sys.path. 
if sys.path[0] != Application.module_path():
    sys.path.insert(1, Application.module_path())

def ListModules(path):
    """
    Lists all Python modules (*.py and *.pyc) in the given path that aren't 
    private (i.e., don't start with "_") and that have the given attribute
    """
    already_processed = set()
    modules = []
    for module_file in os.listdir(path):
        if not re.match(r'[^_].*\.pyc?$', module_file):
            continue
        module_name = module_file.split('.')[0]
        if module_name in already_processed:
            continue
        already_processed.add(module_name)
        module = __import__(".".join(["environment", module_name]),
                            fromlist = [module_name])
        modules.append(module)
    return modules

def MakeHostList(user_dir):
    import host.local
    return [ host.local.LocalHost(user_dir) ]

def MakeEnvironmentList(host_list):
    """    
    Creates the environment list by loading modules from the environment package
    and letting those modules auto-detect available environments.
    
    The environment list is a dictionary of dictionaries of lists, indexed by
    the language name (e.g., "C++") and environment name (e.g., "GCC (Cygwin"),
    with the list giving each version, in order, for that language and
    environment name.
    """
    environment_list = defaultdict(lambda: defaultdict(list))
    all_modules = [ m for m in ListModules(os.path.join(Application.module_path(), 'environment')) if hasattr(m, "configure") ]
    
    progress = QtGui.QProgressDialog("Detecting environments...", QString(), 0, len(all_modules))
    progress.setMinimumDuration(100)
    progress.setWindowTitle(Application.title)
    progress.setWindowModality(Qt.WindowModal)
    
    for module in all_modules:
        if hasattr(module, "NAME"):
            progress.setLabelText("Detecting environments (%s)..." % module.NAME)
        else:
            progress.setLabelText("Detecting environments...")
        module.configure(host_list, environment_list)
        progress.setValue(progress.value() + 1)
        
    return environment_list

# Initialize Qt.
# TODO: Set application icon.
qt_app = QtGui.QApplication(sys.argv)

# Initialize exception handling.
def app_excepthook(type, value, tb):
    import traceback
    lines = traceback.format_exception(type, value, tb)
    lines.insert(0, "Internal error:\n")
    QtGui.QMessageBox.critical(None, Application.title, "".join(lines))
    # Re-raise the exception for the benefit of any attached debugger.
    raise type, value, tb
sys.excepthook = app_excepthook

# Initialize the Application object and application directories.
try:
    app = Application()
except Exception, e:
    QtGui.QMessageBox.critical(None, Application.title, str(e))
    sys.exit(1)

# Initialize user preferences.
# TODO: Integrate my user_prefs with Qt's session management
user_prefs = UserPrefs(app.user_dir)
try:
    user_prefs.load_if_present()
except Exception, e:
    QtGui.QMessageBox.warning(None, Application.title, 
                              "Warning: failed to load user preferences: %s" % str(e))

# Initialize the available hosts and language environments.
host_list = MakeHostList(app.user_dir)
environment_list = MakeEnvironmentList(host_list)

if not environment_list:
    QtGui.QMessageBox.critical(None, Application.title,
                               "Unable to detect any coding environments.  Aborting.")
    sys.exit(1)

# Initialize the main window.
code_widget = CodeWidget(None, app, user_prefs, environment_list)
code_widget.show()

# Run the application.
result = qt_app.exec_()

# Cleanup.
user_prefs.save()

sys.exit(result)
